/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.rivoli.model

import com.googlecode.rivoli.RivoliException

import org.testng.annotations.BeforeMethod
import org.testng.annotations.Test

class ElementTest {
	private ElementDescriptor personDescriptor
	private ElementDescriptor studentDescriptor
	private ElementDescriptor houseDescriptor
	private AttributeDescriptor nameDescriptor

	@BeforeMethod
	void 'create descriptors'() {
		personDescriptor = [getName: {-> 'person'}, getAttributeDescriptors: {-> [nameDescriptor] as Set}, getParent: {-> null}] as ElementDescriptor
		nameDescriptor = [getName: {-> 'name'}, getType: {-> String}] as AttributeDescriptor
		houseDescriptor = [getName: {-> 'house'}, getContainerFor: {-> personDescriptor}, getParent: {-> null}] as ElementDescriptor
		studentDescriptor = [getName: {-> 'student'}, getAttributeDescriptors: {-> [] as Set}, getParent: {-> personDescriptor}] as ElementDescriptor
	}

	@Test
	void 'attribute should be remembered'() {
		Element person = new Element(personDescriptor)

		person.setAttribute('name', 'rolf')

		assert person.getAttribute('name') == 'rolf'
	}

	@Test
	void 'attribute should be nullable'() {
		Element person = new Element(personDescriptor)

		person.setAttribute('name', null)

		assert !person.getAttribute('name')
	}

	@Test(expectedExceptions = RivoliException)
	void 'setting unknown attribute should cause exception'() {
		Element person = new Element(personDescriptor)

		person.setAttribute('gender', 'female')
	}

	@Test(expectedExceptions = RivoliException)
	void 'getting unknown attribute should cause exception'() {
		Element person = new Element(personDescriptor)

		person.getAttribute('gender')
	}

	@Test(expectedExceptions = RivoliException)
	void 'setting attribute with wrong type should cause exception'() {
		Element person = new Element(personDescriptor)

		person.setAttribute('name', 34)
	}

	@Test
	void 'new element should not contain any children'() {
		Element house = new Element(houseDescriptor)

		assert house.children.empty
	}

	@Test
	void 'element should be able to contain children'() {
		Element house = new Element(houseDescriptor)
		Element person = new Element(personDescriptor)

		house.addChild(person)

		assert house.children.size() == 1
		assert house.children.contains(person)
	}

	@Test(expectedExceptions = RivoliException)
	void 'element should only accept children that it is a container for'() {
		Element house = new Element(houseDescriptor)
		Element doghouse = new Element(houseDescriptor)

		house.addChild(doghouse)
	}

	@Test
	void 'attributes should be inherited' () {
		Element student = new Element(studentDescriptor)

		student.setAttribute('name', 'sofie')

		assert student.getAttribute('name') == 'sofie'
	}

	@Test
	void 'element should be able to contain descendants of elements that it is a container for'() {
		Element house = new Element(houseDescriptor)
		Element student = new Element(studentDescriptor)

		house.addChild(student)

		assert house.children.size() == 1
		assert house.children.contains(student)
	}
}